Skip to content

[User Storage Service] browser client, React hooks, injection rendering#268312

Merged
tsullivan merged 51 commits into
elastic:mainfrom
tsullivan:user-storage/browser-client
May 23, 2026
Merged

[User Storage Service] browser client, React hooks, injection rendering#268312
tsullivan merged 51 commits into
elastic:mainfrom
tsullivan:user-storage/browser-client

Conversation

@tsullivan
Copy link
Copy Markdown
Member

@tsullivan tsullivan commented May 7, 2026

Epic: https://github.com/elastic/kibana-team/issues/2769

Summary

Adds the browser foundation for the Core User Storage service (Step 2 of the project; the server-side foundation landed in #256912).

Three pieces:

A. Server-rendered injection.

  • RenderingServicepre-fetches the current user's stored values per request viauserStorage.asScoped(request).getAll()and inlines them under a newuserStorage.valuesfield on`.
  • Bounded by a 50ms timeout (mirroring the existing clusterInfo pattern at rendering_service.tsx:234)
  • skipped for anonymous pages and when asScoped returns null (no profile_uid).

B. Browser client.

  • Three new packages in src/core/packages/user-storage/:
    1. @kbn/core-user-storage-browser (public API: IUserStorageClient, UserStorageProvider, useUserStorage, useUserStorageClient)
    2. @kbn/core-user-storage-browser-internal (UserStorageService, UserStorageClient, UserStorageApi)
    3. @kbn/core-user-storage-browser-mocks.
  • The client seeds an in-memory cache from injected metadata at boot, so get(key) is synchronous at first paint. set/remove write through HTTP and refresh the cache on success.
  • Architectural diagram
    image

C. React hook + provider.

  • useUserStorage(key, default) returns [value, setter] with an Observable-backed subscription, and throws a helpful error when used outside <UserStorageProvider>.
  • useUserStorageClient() is the escape hatch for consumers that depend on remove, getUpdate$, and getUpdateErrors$.

Checklist

Check the PR satisfies following conditions.

Reviewers should verify this PR satisfies this list as well.

  • [ ] Any text added follows EUI's writing guidelines, uses sentence case text and includes i18n support
  • Documentation was added for features that require explanation or tutorials
  • Unit or functional tests were updated or added to match the most common scenarios
  • [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the docker list
  • [ ] This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The release_note:breaking label should be applied in these situations.
  • [ ] Flaky Test Runner was used on any tests changed
  • The PR description includes the appropriate Release Notes section, and the correct release_note:* label is applied per the guidelines
  • Review the backport guidelines and apply applicable backport:* labels.

@tsullivan tsullivan added reviewer:macroscope PR review with Macroscope release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting labels May 7, 2026
@tsullivan
Copy link
Copy Markdown
Member Author

/ci

Comment thread src/core/packages/user-storage/browser/src/user_storage_provider.tsx Outdated
@tsullivan tsullivan added the Team:SharedUX Platform AppEx-SharedUX (formerly Global Experience) t// label May 8, 2026
@tsullivan
Copy link
Copy Markdown
Member Author

/ci

@tsullivan tsullivan marked this pull request as ready for review May 8, 2026 16:55
@tsullivan tsullivan requested review from a team as code owners May 8, 2026 16:55
@infra-vault-gh-plugin-prod
Copy link
Copy Markdown

Pinging @elastic/appex-sharedux (Team:SharedUX)

@tsullivan
Copy link
Copy Markdown
Member Author

Back to draft to add more Scout tests

@tsullivan tsullivan marked this pull request as draft May 8, 2026 21:32
@tsullivan tsullivan requested a review from a team May 8, 2026 21:32
@tsullivan tsullivan requested a review from a team May 19, 2026 23:34
Comment thread src/core/packages/user-storage/common/src/types.ts Outdated
Copy link
Copy Markdown
Contributor

@Dosant Dosant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI-generated review posted by @Dosant. I re-reviewed the updated PR after the recent fixes and focused on remaining behavioral/test issues. One additional note that I could not anchor directly: null currently acts as the server-side removal tombstone, but schemas can still allow null; if null is reserved for removal, registration/write validation should probably reject nullable schemas or the removal representation should change.

Comment thread src/core/packages/user-storage/server-internal/src/routes/index.ts
Comment thread src/core/packages/user-storage/browser/src/use_user_storage.ts Outdated
@tsullivan tsullivan requested review from a team and Dosant May 21, 2026 18:32
};

export const App = ({ userStorage }: { userStorage: IUserStorageClient }) => (
<UserStorageProvider userStorage={userStorage}>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not necessarily in this PR - but I think we can include this provider into our core addContext thing so that apps can access the service without even requiring using the provider directly (similar to what we did to chrome service context)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrote this as a note to myself. It would probably merit attention if it does come up as a request.

Comment thread src/core/packages/user-storage/browser-internal/src/user_storage_client.ts Outdated
@kibanamachine
Copy link
Copy Markdown
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #124 / Entity Analytics - Watchlists @ess @serverless @skipInServerlessMKI Watchlist Lifecycle should remove all entities from the watchlist index when the watchlist is deleted
  • [job] [logs] Scout Lane #46 - serverless-observability_complete / default / local-serverless-observability_complete - Hosts Page - Empty State - should show onboarding page when no data is present

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
core 668 673 +5

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
ml 5.6MB 5.6MB +26.0B

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
core 532.7KB 535.6KB +2.9KB

History

@tsullivan tsullivan merged commit cfa774e into elastic:main May 23, 2026
37 checks passed
patrykkopycinski pushed a commit to patrykkopycinski/kibana that referenced this pull request May 25, 2026
…ng (elastic#268312)

Epic: elastic/kibana-team#2769

## Summary

Adds the browser foundation for the Core User Storage service (Step 2 of
the project; the server-side foundation landed in elastic#256912).

Three pieces:

**A. Server-rendered injection.** 
- RenderingService` pre-fetches the current user's stored values per
request via `userStorage.asScoped(request).getAll()` and inlines them
under a new `userStorage.values` field on `<kbn-injected-metadata>`.
- Bounded by a 50ms timeout (mirroring the existing `clusterInfo`
pattern at `rendering_service.tsx:234`)
- skipped for anonymous pages and when `asScoped` returns `null` (no
`profile_uid`).

**B. Browser client.**
  - Three new packages in `src/core/packages/user-storage/`:
1. `@kbn/core-user-storage-browser` (public API: `IUserStorageClient`,
`UserStorageProvider`, `useUserStorage`, `useUserStorageClient`)
2. `@kbn/core-user-storage-browser-internal` (`UserStorageService`,
`UserStorageClient`, `UserStorageApi`)
    3. `@kbn/core-user-storage-browser-mocks`.
- The client seeds an in-memory cache from injected metadata at boot, so
`get(key)` is synchronous at first paint. `set`/`remove` write through
HTTP and refresh the cache on success.
  - Architectural diagram
<img width="1295" height="631" alt="image"
src="https://github.com/user-attachments/assets/0b3e9113-9ef1-47d7-8f7d-37bf8730e432"
/>

**C. React hook + provider.**
- `useUserStorage(key, default)` returns `[value, setter]` with an
Observable-backed subscription, and throws a helpful error when used
outside `<UserStorageProvider>`.
- `useUserStorageClient()` is the escape hatch for consumers that depend
on `remove`, `getUpdate$`, and `getUpdateErrors$`.

## Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- ~[ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)~
- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- ~[ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)~
- ~[ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.~
- ~[ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed~
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Anton Dosov <anton.dosov@elastic.co>
jcger pushed a commit that referenced this pull request May 26, 2026
…ng (#268312)

Epic: elastic/kibana-team#2769

## Summary

Adds the browser foundation for the Core User Storage service (Step 2 of
the project; the server-side foundation landed in #256912).

Three pieces:

**A. Server-rendered injection.** 
- RenderingService` pre-fetches the current user's stored values per
request via `userStorage.asScoped(request).getAll()` and inlines them
under a new `userStorage.values` field on `<kbn-injected-metadata>`.
- Bounded by a 50ms timeout (mirroring the existing `clusterInfo`
pattern at `rendering_service.tsx:234`)
- skipped for anonymous pages and when `asScoped` returns `null` (no
`profile_uid`).

**B. Browser client.**
  - Three new packages in `src/core/packages/user-storage/`:
1. `@kbn/core-user-storage-browser` (public API: `IUserStorageClient`,
`UserStorageProvider`, `useUserStorage`, `useUserStorageClient`)
2. `@kbn/core-user-storage-browser-internal` (`UserStorageService`,
`UserStorageClient`, `UserStorageApi`)
    3. `@kbn/core-user-storage-browser-mocks`.
- The client seeds an in-memory cache from injected metadata at boot, so
`get(key)` is synchronous at first paint. `set`/`remove` write through
HTTP and refresh the cache on success.
  - Architectural diagram
<img width="1295" height="631" alt="image"
src="https://github.com/user-attachments/assets/0b3e9113-9ef1-47d7-8f7d-37bf8730e432"
/>

**C. React hook + provider.**
- `useUserStorage(key, default)` returns `[value, setter]` with an
Observable-backed subscription, and throws a helpful error when used
outside `<UserStorageProvider>`.
- `useUserStorageClient()` is the escape hatch for consumers that depend
on `remove`, `getUpdate$`, and `getUpdateErrors$`.

## Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- ~[ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)~
- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- ~[ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)~
- ~[ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.~
- ~[ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed~
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Anton Dosov <anton.dosov@elastic.co>
@tsullivan tsullivan deleted the user-storage/browser-client branch May 26, 2026 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes reviewer:macroscope PR review with Macroscope Team:SharedUX Platform AppEx-SharedUX (formerly Global Experience) t// v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants